/*
 * Copyright (c) 2025 [ByteDance Ltd. and/or its affiliates.] and/or its affiliates
 * SPDX-License-Identifier: LGPL v2.1+
*/
#include "FFmpegIOCryptor.h"
#include "FFmpegXORIODecryptor.h"
#include "FFmpegXORIOEncryptor.h"
#include "FFmpegIOCryptorUtils.h"
#include <sys/stat.h>
#include <unistd.h>

const char *kTECryptorType = "cryptor_type";                // int
const char *kFFmpegIOCryptorParam_Step    = "step";       // uint32_t
const char *kFFmpegIOCryptorParam_Length  = "length";     // uint32_t
const char *kFFmpegIOCryptorParam_Key     = "key";        // uint8_t

FFmpegIOCryptor *te_create_ffmpeg_io_decryptor(TECryptorType cryptorType) {
    if (TECryptorType_XOR == cryptorType) {
        return new FFmpegXORIODecryptor();
    } else {
        return nullptr;
    }
}

FFmpegIOEncryptor *te_create_ffmpeg_io_encryptor(TECryptorType cryptorType) {
    if (TECryptorType_XOR == cryptorType) {
        return new FFmpegXORIOEncryptor();
    } else {
        return nullptr;
    }
}

/**
 * Get cryptor type
 * @param url
 * @return
 */
TECryptorType te_get_cryptor_type(const char *url) {
    auto fd = 0;
    int64_t oldPos = 0;

    auto ptr = strstr(url, "pipe:");
    if (ptr) {
        fd = atoi(ptr + 5);
        if (fd > 0) {
            oldPos = lseek(fd, 0, SEEK_CUR);
        }
    }

    AVIOContext *pb = nullptr;
    auto ret = avio_open(&pb, url, AVIO_FLAG_READ);
    if (ret < 0) {
        av_log(NULL, AV_LOG_ERROR, "avio_open failed, ret: %d", ret);
        return TECryptorType_None;
    }

    TECryptorType cryptorType = TECryptorType_None;
    int64_t pos = 0;
    uint32_t bdveTagSize = 0, tagSize, tagName;

    auto size = avio_size(pb);
    if (size < 0) {
        av_log(NULL, AV_LOG_ERROR, "avio_size failed, ret: %" PRId64, size);
        goto end;
    }

    pos = avio_seek(pb, size - 4, SEEK_SET);
    if (pos < 0) {
        av_log(NULL, AV_LOG_ERROR, "avio_seek failed, ret: %" PRId64, size);
        goto end;
    }

    bdveTagSize = avio_rb32(pb); // bdve box size
    pos = avio_seek(pb, size - bdveTagSize, SEEK_SET);
    if (pos < 0) {
        av_log(NULL, AV_LOG_ERROR, "avio_seek failed, ret: %" PRId64, size);
        goto end;
    }

    tagSize = avio_rb32(pb); // bdve tag size
    tagName = avio_rb32(pb); // bdve tag
    if (tagName == MKBETAG('b', 'd', 'v', 'e')) {
        if (FFmpegIOCryptorUtils::findTag(pb, MKBETAG('c', 'r', 'p', 't'), tagSize - 8, &tagSize)) {
            cryptorType = (TECryptorType) avio_rb32(pb);
        }
    }

end:
    avio_close(pb);

    if (fd > 0) {
        lseek(fd, oldPos, SEEK_SET);
    }

    return cryptorType;
}
